package com.yueya.system.service;

import com.yueya.auth.config.AuthProperties;
import com.yueya.auth.model.Account;
import com.yueya.auth.model.TokenDto;
import com.yueya.auth.realm.Principal;
import com.yueya.auth.service.AccountInfoProvider;
import com.yueya.auth.utils.JwtUtil;
import com.yueya.common.base.BaseService;
import com.yueya.common.util.DateUtils;
import com.yueya.system.dao.tables.TokenManage;
import com.yueya.system.dao.tables.daos.TokenManageDao;
import com.yueya.system.dao.tables.pojos.SysUserDO;
import com.yueya.system.dao.tables.pojos.TokenManageDO;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import org.jooq.Condition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.sql.Timestamp;
import java.util.*;

@Service
public class SysTokenService extends BaseService<TokenManageDO> {

    @Autowired
    private AuthProperties properties;

    @Autowired
    private TokenManageDao manageDao;

    @Autowired
    private AccountInfoProvider provider;
    @Override
    public List<Condition> getConditions(TokenManageDO tokenManageDO) {
        return Collections.emptyList();
    }

    public TokenManageDO fetchById(String tokenId) {
       return manageDao.fetchOneByTokenId(tokenId);
    }



    public String getRefreshToken(String token, String host, String agent) throws InvalidKeySpecException, NoSuchAlgorithmException {
        Jws<Claims> jws = JwtUtil.parseJwtPayload(token, properties.getPublicKey(),properties.getSignMode());
        String tokenId =jws.getBody().getId();
        Date createTime = jws.getBody().getIssuedAt();
        Date curDate = new Date();

       /* Date lastEffectTime = DateUtils.addHours(createTime,properties.getRefreshTime());
        if(lastEffectTime.getTime() < curDate.getTime()) {
            expireToken(tokenId);
            return null;
        }*/
        TokenManageDO tokenManageDO = fetchById(tokenId);
        if (tokenManageDO == null) {
            return null;
        }
        // 检测浏览器和主机地址，如果和之前不一样，不允许刷新token
        if (!host.equals(tokenManageDO.getHost()) && !agent.equals(tokenManageDO.getAgent())) {
            expireToken(tokenId);
            return null;
        }
        // 查看refreshToken是否过期，如果过期则不签发新的accesstoken
        Date refresh = DateUtils.addHours(tokenManageDO.getCreateGmt(),properties.getRefreshTime());
        if (refresh.getTime() <= curDate.getTime()) {
            expireToken(tokenId);
            return null;
        }
        tokenManageDO.setAgent(agent);
        tokenManageDO.setHost(host);
        Date date = new Date();
        tokenManageDO.setLastCheckTime(new Timestamp(date.getTime()));
        manageDao.update(tokenManageDO);
        String userID = String.valueOf(tokenManageDO.getUserId());
        List<String> roles = new ArrayList<>(provider.loadRoles(userID));
        List<String> pers = new ArrayList<>(provider.loadPermissions(userID));
        Account account = provider.loadAccount(tokenManageDO.getLoginName());
        return JwtUtil.createJwtToke(new Principal(account,roles,pers),tokenId,date,properties);
    }

    public void expireToken(String tokenID) {
        manageDao.deleteByCondition(TokenManage.TOKEN_MANAGE.TOKEN_ID.eq(tokenID));
    }


    public void insert(TokenDto tokenDto) {
        TokenManageDO manageDO = new TokenManageDO();
        manageDO.setUserId(Integer.valueOf(tokenDto.getUserId()));
        manageDO.setLoginName(tokenDto.getLoginName());
        manageDO.setTokenId(tokenDto.getTokenId());
        Timestamp timestamp = new Timestamp(tokenDto.getCreateDate().getTime());
        manageDO.setCreateGmt(timestamp);
        manageDO.setLastCheckTime(timestamp);
        manageDO.setHost(tokenDto.getHost());
        manageDO.setAgent(tokenDto.getAgent());
        manageDO.setName(tokenDto.getName());
        manageDao.insert(manageDO);
    }

    public List<TokenManageDO> page(int limit, int offset, TokenManageDO tokenManage) {
        return manageDao.page(offset,limit,getConditions(tokenManage));
    }

    public long countByCondition(TokenManageDO tokenManageDO) {
        return manageDao.countByCondition(getConditions(tokenManageDO));
    }
}
